import { injectable, inject } from 'inversify';
import { DataSource, Repository, MoreThan } from 'typeorm';
import { Token } from '../../../domain/entities/token.entity';
import { IRepository } from './interfaces/IRepository';
import { TYPES } from '../../ioc/types';
import { LoggerService } from '../../logging/logger.service';

@injectable()
export class TokenRepository implements IRepository<Token> {
  private repository: Repository<Token>;

  constructor(
    @inject(TYPES.DataSource) dataSource: DataSource,
    @inject(TYPES.LoggerService) private logger: LoggerService
  ) {
    this.repository = dataSource.getRepository(Token);
  }

  async save(token: Token): Promise<Token> {
    try {
      return await this.repository.save(token);
    } catch (error: any) {
      this.logger.error(`Error saving token: ${error.message}`);
      throw error;
    }
  }

  async findById(id: string): Promise<Token | null> {
    try {
      return await this.repository.findOneBy({ id });
    } catch (error: any) {
      this.logger.error(`Error finding token by ID: ${error.message}`);
      return null;
    }
  }

  async findOne(options: any): Promise<Token | null> {
    try {
      return await this.repository.findOne(options);
    } catch (error: any) {
      this.logger.error(`Error finding token: ${error.message}`);
      return null;
    }
  }

  async find(options?: any): Promise<Token[]> {
    try {
      return await this.repository.find(options || {});
    } catch (error: any) {
      this.logger.error(`Error finding tokens: ${error.message}`);
      return [];
    }
  }

  async delete(id: string): Promise<void> {
    try {
      await this.repository.delete(id);
    } catch (error: any) {
      this.logger.error(`Error deleting token: ${error.message}`);
      throw error;
    }
  }

  async findValidTokenByUserAndType(userId: string, type: string): Promise<Token | null> {
    try {
      // Find a valid token that has not expired
      return await this.repository.findOne({
        where: {
          userId,
          type,
          expiresAt: MoreThan(new Date())
        },
        order: {
          createdAt: 'DESC'
        }
      });
    } catch (error: any) {
      this.logger.error(`Error finding valid token: ${error.message}`);
      return null;
    }
  }

  async deleteExpiredTokens(): Promise<void> {
    try {
      await this.repository.delete({
        expiresAt: MoreThan(new Date())
      });
    } catch (error: any) {
      this.logger.error(`Error deleting expired tokens: ${error.message}`);
    }
  }
}
